#target "indesign"
// Apply a user-selected GREP query to every INDD document inside a chosen folder.
(function () {
    if (!app || app.name !== "Adobe InDesign") {
        alert("请在 Adobe InDesign 中运行此脚本。");
        return;
    }

    var grepQueries = collectGrepQueries();
    if (!grepQueries.length) {
        alert("未找到任何 GREP 预设。请先在查找/替换面板中保存至少一个 GREP 预设。");
        return;
    }

    var folder = Folder.selectDialog("请选择包含 INDD 文件的文件夹");
    if (!folder) {
        return;
    }

    var includeSubfolders = confirm("是否同时处理子文件夹中的 INDD 文件？\n选择“确定”包含子文件夹，选择“取消”仅处理当前文件夹。");
    var inddFiles = [];
    collectInddFiles(folder, includeSubfolders, inddFiles);

    if (!inddFiles.length) {
        alert("所选位置中未找到任何 INDD 文件。");
        return;
    }

    var queryName = promptForQuery(grepQueries);
    if (!queryName) {
        return;
    }

    var originalInteraction = app.scriptPreferences.userInteractionLevel;
    var originalRedraw = app.scriptPreferences.enableRedraw;
    app.scriptPreferences.userInteractionLevel = UserInteractionLevels.NEVER_INTERACT;
    app.scriptPreferences.enableRedraw = false;

    var openDocsMap = mapCurrentlyOpenDocs();
    var processed = 0;
    var failures = [];

    try {
        for (var i = 0; i < inddFiles.length; i++) {
            var file = inddFiles[i];
            var doc = openDocsMap[file.fsName];
            var openedHere = false;

            try {
                if (!doc) {
                    doc = app.open(file, false);
                    openedHere = true;
                } else if (app.documents.length && doc !== app.activeDocument) {
                    app.activeDocument = doc;
                }

                resetGrepPreferences();
                app.loadFindChangeQuery(queryName, SearchModes.GREP_SEARCH);
                doc.changeGrep();
                doc.save();
                processed++;
            } catch (docError) {
                failures.push(file.fsName + " → " + docError);
            } finally {
                if (openedHere && doc && doc.isValid) {
                    try {
                        doc.close(SaveOptions.NO);
                    } catch (_closeError) {
                        // Ignore close errors so the script can continue.
                    }
                }
            }
        }
    } finally {
        resetGrepPreferences();
        app.scriptPreferences.userInteractionLevel = originalInteraction;
        app.scriptPreferences.enableRedraw = originalRedraw;
    }

    var message = "已处理文档数：" + processed + "/" + inddFiles.length;
    if (failures.length) {
        message += "\n以下文件处理失败：\n" + failures.join("\n");
    }
    alert(message);

    function collectInddFiles(rootFolder, recurse, bucket) {
        if (!rootFolder || !rootFolder.exists) {
            return;
        }
        var entries = rootFolder.getFiles();
        for (var i = 0; i < entries.length; i++) {
            var entry = entries[i];
            if (entry instanceof Folder) {
                if (recurse) {
                    collectInddFiles(entry, recurse, bucket);
                }
                continue;
            }
            if (/\.indd$/i.test(entry.name)) {
                bucket.push(File(entry.fsName));
            }
        }
    }

    function collectGrepQueries() {
        var results = [];
        var seen = {};
        var sources = getQueryFolders();

        for (var i = 0; i < sources.length; i++) {
            var folder = sources[i];
            if (!folder || !folder.exists) {
                continue;
            }

            var files = folder.getFiles(function (item) {
                return item instanceof File && /\.xml$/i.test(item.name);
            });

            for (var j = 0; j < files.length; j++) {
                var name = files[j].displayName.replace(/\.xml$/i, "");
                if (!seen[name]) {
                    seen[name] = true;
                    results.push(name);
                }
            }
        }

        results.sort();
        return results;
    }

    function getQueryFolders() {
        var folders = [];

        // Application-level presets (varies by installation).
        maybePushFolder(folders, new Folder(Folder.appPackage.fullName + "/Presets/Find-Change Queries/GREP"));
        maybePushFolder(folders, new Folder(Folder.appPackage.fullName + "/Resources/Find-Change Queries/GREP"));

        // User-level presets at %APPDATA%/Adobe/InDesign/Version */*/Find-Change Queries/GREP
        var userBase = new Folder(Folder.userData.fullName + "/Adobe/InDesign");
        if (userBase.exists) {
            var versionFolders = userBase.getFiles(function (item) {
                return item instanceof Folder;
            });

            for (var i = 0; i < versionFolders.length; i++) {
                var versionFolder = versionFolders[i];
                maybeAddQueryFolder(versionFolder);

                var localeFolders = versionFolder.getFiles(function (child) {
                    return child instanceof Folder;
                });

                for (var j = 0; j < localeFolders.length; j++) {
                    maybeAddQueryFolder(localeFolders[j]);
                }
            }
        }

        return folders;

        function maybeAddQueryFolder(baseFolder) {
            maybePushFolder(folders, new Folder(baseFolder.fsName + "/Find-Change Queries/GREP"));
        }
    }

    function maybePushFolder(list, folder) {
        if (!folder || !folder.exists) {
            return;
        }
        var path = folder.fsName;
        for (var i = 0; i < list.length; i++) {
            if (list[i].fsName === path) {
                return;
            }
        }
        list.push(folder);
    }

    function promptForQuery(queries) {
        var dialog = new Window("dialog", "选择 GREP 预设");
        dialog.alignChildren = "fill";

        dialog.add("statictext", undefined, "请选择要应用的 GREP 预设：");

        var list = dialog.add("dropdownlist", undefined, queries);
        list.selection = 0;

        var buttons = dialog.add("group");
        buttons.alignment = "right";
        buttons.add("button", undefined, "确定", { name: "ok" });
        buttons.add("button", undefined, "取消", { name: "cancel" });

        var result = dialog.show();
        if (result !== 1 || !list.selection) {
            return null;
        }
        return list.selection.text;
    }

    function mapCurrentlyOpenDocs() {
        var map = {};
        var docs = app.documents;
        for (var i = 0; i < docs.length; i++) {
            var doc = docs[i];
            try {
                map[doc.fullName.fsName] = doc;
            } catch (_e) {
                // Skip unsaved documents.
            }
        }
        return map;
    }

    function resetGrepPreferences() {
        app.findGrepPreferences = NothingEnum.nothing;
        app.changeGrepPreferences = NothingEnum.nothing;
    }
})();

